package edu.gatech.mobile.scene.ui.image;

import java.util.ArrayList;
import java.util.List;

import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.MatOfDMatch;
import org.opencv.core.Range;
import org.opencv.features2d.DMatch;
import org.opencv.highgui.Highgui;
import org.opencv.imgproc.Imgproc;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Point;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.ViewGroup.LayoutParams;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import edu.gatech.mobile.scene.AppConstants;
import edu.gatech.mobile.scene.AppConstants.RELATIVE_TO_HORIZON;
import edu.gatech.mobile.scene.ApplicationContext;
import edu.gatech.mobile.scene.R;
import edu.gatech.mobile.scene.image.util.HistogramCompareUtil;
import edu.gatech.mobile.scene.image.util.MatUtil;
import edu.gatech.mobile.scene.model.ColorHistogram;
import edu.gatech.mobile.scene.model.ImageInfo;
import edu.gatech.mobile.scene.model.LabelInfo;
import edu.gatech.mobile.scene.model.MaskInfo;
import edu.gatech.mobile.scene.provider.impl.ImageInfoDBImpl;
import edu.gatech.mobile.scene.provider.impl.LabelInfoDBImpl;

public class ActiveEvaluationActivity extends Activity {

	
	private static final int LABEL_IMAGE = Menu.FIRST;	
	private static final int K = 1; 

	
	private LabelInfoDBImpl labelDB;
	private ImageInfoDBImpl imageDB;
	
	
	private double slope;
	private double height;
	private double intercept;
	private LabelView drawing;
	private String imagePath;
	
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

			setContentView(R.layout.evaluation_view);
			
			//read in the image to be evaluated
			imagePath = getIntent().getExtras().getString(AppConstants.BUNDLE_IMAGE_KEY);
			Bitmap image = BitmapFactory.decodeFile(imagePath);
			Bitmap mutableMap  =  image.copy(Bitmap.Config.ARGB_8888, true);
			image.recycle();
			
			//initialize neccessary variables
			drawing = new LabelView(this, mutableMap);
			addContentView(drawing, new LayoutParams(640,480));	
			labelDB = new LabelInfoDBImpl(this);
			imageDB = new ImageInfoDBImpl(this);
			
			ApplicationContext context = (ApplicationContext) getApplicationContext();
			
			//Classify the image if there are enough training data
			if(context.getOnMaskImages().size()>0 && context.getBelowMaskImages().size()>0 && context.getAboveMaskImages().size()>0){
				evaluationMethod2(imagePath);
			}
			else{
				StringBuilder sb = new StringBuilder();
				if(context.getBelowMaskImages().size()<1){
					sb.append("No Training Masks from Below the Horizon\n");
				}
				if(context.getOnMaskImages().size()<1){
					sb.append("No Training Masks from On the Horizon\n");
				}
				if(context.getAboveMaskImages().size()<1){
					sb.append("No Training Masks from Above the Horizon\n");
				}
				Toast.makeText(this, sb.toString(), Toast.LENGTH_LONG).show();
			}
			

			//load in all of the labels
			for(LabelInfo label : labelDB.getLabels()){
				Integer color  = label.getColor();
		        TextView tv = new TextView(this);
		        tv.setText(label.getLabelName().toLowerCase());
		        tv.setTag(label.getLabelName()+":"+color);
		        tv.setTextColor(color);
		        LinearLayout ll = (LinearLayout)findViewById(R.id.label_text);
		        ll.addView(tv);
			}
	}
	
	/**
	 * Evaluate the image at the given path
	 * @param imagePath where the image is located
	 */
	private void evaluationMethod2(String imagePath){

		ApplicationContext context = (ApplicationContext) getApplicationContext();

		Bitmap image = BitmapFactory.decodeFile(imagePath);	
		ImageInfo classifyingImageInfo = imageDB.getImageByName(imagePath);
		
		//We create an image to show the result and 
		//it's a factor of AppConstants.BLOCK_SIZE smaller, so 1 pixel represents the whole patch
		Bitmap comparisonBitmap2 = Bitmap.createBitmap(
				image.getWidth()/AppConstants.BLOCK_SIZE, image.getHeight()/AppConstants.BLOCK_SIZE,
				Bitmap.Config.ARGB_8888);
		
		
		//create temporary images
		Mat origMat = Highgui.imread(imagePath);
		Mat origMat1 = Highgui.imread(imagePath);
		Mat grayMat = new Mat(origMat1.height(), origMat1.width(),CvType.CV_8UC1);
		Imgproc.cvtColor(origMat1, grayMat, Imgproc.COLOR_RGB2GRAY);		
		origMat1.release();
		
		//compute the horizon line
		Point[] horizonPoints = classifyingImageInfo.getHorizonPoints();
		Point point1 = horizonPoints[0];
		Point point2 = horizonPoints[1];
		slope = (point1.y - point2.y) * 1.0 / (point1.x - point2.x)
				* 1.0;
		height = ((point2.y - point1.y) * point1.x)
				/ (point2.x - point1.x);
		intercept = point1.y - height;
		
		int mutableHeight = image.getHeight();
		int mutableWidth = image.getWidth();
		image.recycle();
		
		//Evaluate one patch at a time
		for (int h = 0; h < mutableHeight; h += AppConstants.BLOCK_SIZE) {
			for (int w = 0; w < mutableWidth; w += AppConstants.BLOCK_SIZE) {
				Integer machedColor = null;
				RELATIVE_TO_HORIZON horizonPosition;
				int leftY = (int) (w * slope + intercept);
				int rightY = (int) ((w + AppConstants.BLOCK_SIZE) * slope + intercept);

				if(h > leftY && h >rightY && (h+AppConstants.BLOCK_SIZE) > leftY && (h+AppConstants.BLOCK_SIZE)> rightY){
					horizonPosition = RELATIVE_TO_HORIZON.BELOW;
				}
				else if(h < leftY && h < rightY && (h+AppConstants.BLOCK_SIZE) < leftY && (h+AppConstants.BLOCK_SIZE) <rightY ){
					horizonPosition = RELATIVE_TO_HORIZON.ABOVE;
				}
				else{
					horizonPosition = RELATIVE_TO_HORIZON.ON;
				}				
				
				if (h + AppConstants.BLOCK_SIZE <=mutableHeight
						&& w + AppConstants.BLOCK_SIZE <= mutableWidth) {
					
					//get the sub-matrix of the patch
					Mat colorMat = origMat.submat(new Range(h, h+AppConstants.BLOCK_SIZE), new Range(w, w + AppConstants.BLOCK_SIZE));
					Mat maskMat = grayMat.submat(new Range(h, h+AppConstants.BLOCK_SIZE), new Range(w, w + AppConstants.BLOCK_SIZE));
					List<Mat> classifyHist = HistogramCompareUtil.RGBHistCalc(colorMat, maskMat);
					ColorHistogram colorHisto = new ColorHistogram(classifyHist);
					
					//constructing descriptor
					Mat currentFeatureVector = new Mat (1, AppConstants.COLOR_HISTOMGRAM_BIN_SIZE*3, CvType.CV_32F);
					MaskInfo currentMask = new MaskInfo();
					currentMask.setHistograms(colorHisto);
					MatUtil.fillMatcherMat(currentFeatureVector, currentMask, 0);

					List<MatOfDMatch> matches = new ArrayList<MatOfDMatch>();
					List<Integer> correctMasks = null;
					
					//selecting the correct training data based on horizon location.
					if(horizonPosition.equals(AppConstants.RELATIVE_TO_HORIZON.ON)){
						//System.out.println("On: " + GlobalContext.onMatcher.getTrainDescriptors().size());
						context.getOnMatcher().knnMatch(currentFeatureVector, matches, K);
						correctMasks = context.getOnMaskColors();
					}
					if(horizonPosition.equals(AppConstants.RELATIVE_TO_HORIZON.ABOVE)){
						//System.out.println("Above: " + GlobalContext.aboveMatcher.getTrainDescriptors().size());
						context.getAboveMatcher().knnMatch(currentFeatureVector, matches, K);
						correctMasks = context.getAboveMaskColors();
					}
					if(horizonPosition.equals(AppConstants.RELATIVE_TO_HORIZON.BELOW)){
						//System.out.println("Below: " + GlobalContext.belowMatcher.getTrainDescriptors().size());
						context.getBelowMatcher().knnMatch(currentFeatureVector, matches, K);
						correctMasks = context.getBelowMaskColors();
					}
					currentFeatureVector.release();
					
					//draw the label color
					machedColor = correctMasks.get(matches.get(0).toList().get(0).trainIdx);
					
					comparisonBitmap2.setPixel(w / AppConstants.BLOCK_SIZE, h/ AppConstants.BLOCK_SIZE, machedColor);
					
					for(Mat classifyMat : classifyHist){
						classifyMat.release();
					}					
				}
			}
		}
		
		//rescale the result map
		Bitmap map = Bitmap.createScaledBitmap(comparisonBitmap2, mutableWidth, mutableHeight, false);
		comparisonBitmap2.recycle();
		drawing.drawOnCanvas(map);
		map.recycle();
						
		origMat.release();
		origMat1.release();
		grayMat.release();
		
		
	}

	public void onResume() {
		super.onResume();
	}
	
	public void onPause(){
		drawing=null;
		super.onPause();
		this.finish();
		System.gc();
		System.out.println("JW Active Eval Finished");
	}
	
	public boolean onCreateOptionsMenu(Menu menu) {
		menu.add(0,LABEL_IMAGE , 0, "Label This Image").setShortcut('3', 'c');
		return true;
	}
	
	
	/**
	 * Handles the menu item click events
	 */
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case LABEL_IMAGE:
			Bundle bdl = new Bundle();
			bdl.putString(AppConstants.BUNDLE_IMAGE_KEY, imagePath);
   			Intent i = new Intent(getApplicationContext(), ImageViewActivity.class);
   			i.putExtras(bdl);
   			startActivity(i);
   			drawing=null;
   			this.finish();
   			System.gc();
   			System.out.println("JW Active Eval Finished");

		default:
			return super.onOptionsItemSelected(item);
		}
	}


}
